import datetime
import logging
import json
import re
import time

import requests

from base.connection import mongodb_util, get_db_session
from common.definition import AgencyType, PayStatus
from conf import config
from decimal import Decimal

from daemon import tasks
from helper import template_messages
from helper.mp_helper import fetch_access_token, fetch_simple_access_token
from helper.order import get_order
from sqlalchemy.exc import IntegrityError
from util.date_util import convert_ts_2_date
from util.str_util import replace_emoji

logger = logging.getLogger("wechat")


def get_user(openid):
    """
    获取用户信息
    :param openid:
    :return:
    """
    openid = str(openid)
    try:
        db = mongodb_util.db
        user = db.users.find_one({"openid": openid})
        return user
    except Exception as e:
        logger.exception(e)
        return None


def get_clerk_oid(store_id):
    """
    获取门店/供应商和店员open_id列表

    get_clerk_oid(296)

    :param store_id:
    :return:
    """
    class User(object):
        pass

    class Agency(object):
        pass

    class UserAgency(object):
        pass

    session = get_db_session([
        {"db_table": "ebt_user", "model": User},
        {"db_table": "ebt_agency", "model": Agency},
        {"db_table": "ebt_user_agency", "model": UserAgency},
    ])

    oid_list = list()
    agencies = session.query(Agency).filter_by(
        ebf_agency_parent_id=store_id,
        ebf_agency_type=4).order_by(Agency.ebf_agency_id.desc()).all()
    for a in agencies:
        agency_id = a.ebf_agency_id
        ua = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
        if ua and ua.ebf_ua_bind_user_id:
            oid_list.append(ua.ebf_ua_bind_user_id)

    ua2 = session.query(UserAgency).filter_by(ebf_agency_id=store_id).first()
    if ua2 and ua2.ebf_ua_bind_user_id:
        oid_list.append(ua2.ebf_ua_bind_user_id)
    session.close()
    return oid_list


def get_order_notice_oid(order_id):
    """
    获取订单通知open_id列表

    get_order_notice_oid(15554810983567980)

    :param order_id:
    :return:
    """
    order = get_order(order_id)
    store_id = order.sdef_order_store_id
    supplier_id = order.sdef_order_supplier_id
    oid_list = list()
    if store_id > 1:
        oid_list = get_clerk_oid(store_id) + config.COMMON_NOTICE_RECEIVER
    else:
        oid_list = config.COMMON_NOTICE_RECEIVER
    if supplier_id > 1:
        supplier_oid_list = get_clerk_oid(supplier_id)
        oid_list += supplier_oid_list
    return oid_list


def generate_partner_qrcode(agency_uid):
    """
    生成合伙人二维码内容

    generate_partner_qrcode("b880ec4a-d155-11e9-a8ba-5254005e893b")
    'http://weixin.qq.com/q/02SLX2IIKIeBi10000007e'

    :param agency_uid:
    :return:
    """

    appid = config.MP_APP_ID
    secret = config.MP_APP_SECRET

    # 获取微信的二维码
    base_url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={token}"
    access_token = fetch_simple_access_token(appid, secret)
    url = base_url.format(token=access_token)
    logger.debug(url)

    # 二维码内容拼接
    scene_str = "uid_" + agency_uid
    action_name = "QR_LIMIT_STR_SCENE"
    data = dict(
        action_name=action_name,
        action_info={"scene": {"scene_str": scene_str}}
    )
    logger.debug("data=%s" % data)

    counter = 0
    flag = True
    while counter < 6 and flag:
        if counter == 3:
            access_token = fetch_access_token(appid, secret, reset=True).get("access_token", "")
            url = base_url.format(token=access_token)

        r = requests.post(url=url, data=json.dumps(data).encode(), timeout=30)
        logger.debug(r.text)
        """
            返回结果示例：
            {"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm3sUw==",
            "expire_seconds":60,"url":"http:\/\/weixin.qq.com\/q\/kZgfwMTm72WWPkovabbI"}
        """
        r = r.json()
        qr_wechat_url = r.get("url", None)
        if qr_wechat_url:
            flag = False
        else:
            errcode = r.get("errcode", 0)
            logger.error("errcode=%s, counter=%s" % (errcode, counter))
        counter += 1

    if not qr_wechat_url:
        logger.error("result=%s" % r)
        raise Exception("qr_wechat_url为空: scene_str: %s" % scene_str)

    return qr_wechat_url


class UserHelper(object):
    @staticmethod
    def get_user(open_id):
        class User(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        session.close()
        return user

    @staticmethod
    def update_level(open_id, recommend_oid):
        """修改用户拥有酒卡身份"""

        if not recommend_oid and open_id:
            return

        class User(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        recommend_user = session.query(User).filter_by(ebf_user_id=recommend_oid).first()
        level = user.ebf_user_level if user else 0
        if user and recommend_user and recommend_user.ebf_user_level and not user.ebf_user_level:
            user.ebf_user_level = 1
            level = 1
            logger.info(f"更新用户级别 open_id={open_id}")
            session.commit()
        session.close()
        return level

    @staticmethod
    def send_card(open_id):
        """
        给用户发卡
        """

        class User(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if user and not user.ebf_user_level:
            user.ebf_user_level = 1
            logger.info(f"发卡: 更新用户级别为1 open_id={open_id}")
            session.commit()

            logger.info(f"发卡: 发送中奖结果通知 open_id={open_id}")
            template_messages.lucky_draw_notice(open_id)
        session.close()

    @staticmethod
    def update_agency_uid(open_id, agency_uid):
        """
        更新用户所属合伙人

        :param open_id: 用户ID
        :param agency_uid: 合伙人UID
        :return:
        """
        if not open_id and agency_uid:
            return

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
        if not agency:
            logger.error(f"更新合伙人：合伙人不存在 open_id={open_id} agency_uid={agency_uid}")
            session.close()
            return

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            logger.error(f"更新合伙人：用户不存在 open_id={open_id} agency_uid={agency_uid}")
            session.close()
            return

        old_agency_uid = user.ebf_user_agency_uid
        if old_agency_uid == agency_uid:
            logger.info(f"更新合伙人：新旧合伙人一致无需更新 open_id={open_id} agency_uid={agency_uid}")
            session.close()
            return

        logger.info(f"更新合伙人：open_id={open_id} old_agency_uid={old_agency_uid} new_agency_uid={agency_uid}")
        user.ebf_user_agency_uid = agency_uid
        session.commit()
        session.close()
        return user

    @staticmethod
    def create_user(user_dict, agency_uid, recommend_user=""):
        """
        创建用户
        :param user_dict:
          {
       "subscribe": 1,
       "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
       "nickname": "Band",
       "sex": 1,
       "language": "zh_CN",
       "city": "广州",
       "province": "广东",
       "country": "中国",
       "headimgurl":  "http://wx.qlogo.cn/mmopen/g3MonUZtNHk
       dmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4
    eMsv84eavHiaiceqxibJxCfHe/0",
      "subscribe_time": 1382694957,
      "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
      "remark": "",
      "groupid": 0,
      "tagid_list":[128,2]
    }

    没关注的话只能获取如下信息

     {"subscribe":0,"openid":"o7qyl0iYIEldo1SxrDonwrIxzDpk","tagid_list":[]}
        :param agency_uid:
        :param recommend_user:
        :return:
        """
        open_id = user_dict["openid"]
        logger.info("创建用户：user_dict=%s,agency_uid=%s" % (open_id, agency_uid))

        class User(object):
            pass

        class UserInfo(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_user_info", "model": UserInfo},
        ])

        # 设置用户等级 普通用户=0 会员等级=1-10 VIP=10
        user_level = 0
        agency = UserHelper.get_agency(agency_uid)
        agency_id = agency.ebf_agency_id
        agency_type = agency.ebf_agency_type
        if agency_type == AgencyType.STORE and UserHelper.get_agency_openid(agency_id) == recommend_user:
            # 门店直推用户给VIP享受内供价资格
            # user_level = 10
            pass

        user = User()
        try:
            user.ebf_user_id = open_id
            user.ebf_user_account = user_dict.get("unionid", open_id)
            user.ebf_user_password = ""
            user.ebf_user_headurl = user_dict.get("headimgurl")

            user.ebf_user_nickname = replace_emoji(user_dict.get("nickname", "未关注"))
            user.ebf_user_gender = user_dict.get("sex", 0)
            user.ebf_user_type = 0
            user.ebf_user_account_type = 2
            user.ebf_user_create_date = convert_ts_2_date(
                user_dict.get("subscribe_time", str(time.time()).split(".")[0])) - datetime.timedelta(hours=8)
            user.ebf_user_factory_id = config.FACTORY_ID
            user.ebf_user_agency_uid = agency_uid
            user.ebf_user_recommend_user = recommend_user if recommend_user else ""
            user.ebf_user_level = user_level
            session.add(user)
            session.flush()

            user_info = UserInfo()
            user_info.ebf_user_id = user.ebf_user_id
            user_info.ebf_ui_province = user_dict.get("province")
            user_info.ebf_ui_city = user_dict.get("city")
            user_info.ebf_ui_area = ""
            session.add(user_info)
            session.flush()
            session.commit()
            # 触发新用户注册事件
            tasks.user_registered.delay(open_id)
        except IntegrityError:
            session.rollback()

        class NewUser(object):
            pass

        cursor = get_db_session([
            {"db_table": "ebt_user", "model": NewUser}
        ])
        user = cursor.query(NewUser).filter_by(ebf_user_id=open_id).first()
        cursor.close()
        session.close()
        return user

    @staticmethod
    def update_user(user_dict):
        logger.info("更新用户信息：user_dict=%s" % user_dict)
        open_id = user_dict["openid"]

        class User(object):
            pass

        class UserInfo(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_user_info", "model": UserInfo},
        ])
        user = session.query(User).filter_by(ebf_user_id=open_id, ebf_user_factory_id=config.FACTORY_ID).first()
        if user is None:
            return False

        try:
            user.ebf_user_account = user_dict.get("unionid", open_id)
            user.ebf_user_headurl = user_dict.get("headimgurl")
            user.ebf_user_nickname = replace_emoji(user_dict.get("nickname", "未关注"))
            user.ebf_user_gender = user_dict.get("sex", 0)
            user.ebf_user_create_date = convert_ts_2_date(
                user_dict.get("subscribe_time", str(time.time()).split(".")[0])) - datetime.timedelta(hours=8)
            user.ebf_user_factory_id = config.FACTORY_ID

            user_info = session.query(UserInfo).filter_by(ebf_user_id=open_id)
            user_info.ebf_ui_province = user_dict.get("province")
            user_info.ebf_ui_city = user_dict.get("city")
            user_info.ebf_ui_area = ""
            session.flush()
            session.commit()
            session.close()
        except Exception as e:
            logger.exception(e)
            session.rollback()
            session.close()
            return False
        return True

    @staticmethod
    def is_buy_wine(open_id):
        """
        判断用户是否享受过特惠购酒
        :param open_id:
        :return:
        """
        class Order(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_order", "model": Order},
        ])

        _filters = dict(
            sdef_order_device_id=open_id,
            sdef_order_factory_uid=config.FACTORY_UID,
            sdef_order_pay_status=1,
            sdef_order_type=4,  # 4=特惠订单
            sdef_order_is_delete=0,
            sdef_order_fee=Decimal("79.00"),
            sdef_order_balance_fee=Decimal("0.00"),
        )
        order = session.query(Order).filter_by(**_filters).first()
        if order:
            return True
        return False

    @staticmethod
    def add_recommend_number(open_id):
        """
        增加推荐新用户人数

        UserHelper.add_recommend_number("o7qyl0i6R30kbFS7KPFVGwYb05pY")

        :param open_id:
        :return:
        """

        class User(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])
        user = session.query(User).filter_by(ebf_user_id=open_id, ebf_user_factory_id=config.FACTORY_ID).first()
        recommend_open_id = user.ebf_user_recommend_user
        if not recommend_open_id:
            logger.error(f"增加推荐新用户人数: 没有推荐人 open_id={open_id}")
            session.close()
            return

        recommender = session.query(User).filter_by(ebf_user_id=recommend_open_id,
                                                    ebf_user_factory_id=config.FACTORY_ID).first()
        if not recommender:
            logger.error(f"增加推荐新用户人数: 没有推荐人 open_id={open_id}")
            session.close()
            return

        recommend_number = recommender.ebf_user_recommend_number
        recommend_number += 1
        recommender.ebf_user_recommend_number = recommend_number
        session.commit()
        session.close()
        logger.info(f"增加推荐新用户人数：open_id={open_id} recommender={recommend_open_id} 推荐第{recommend_number}人")


    @staticmethod
    def get_online_store_info(open_id):
        """
        获取用户线上小商信息
        高级门店用户返回门店信息，否则返回默认: '',''

        UserHelper.get_online_store_info("o7qyl0vKx54jB05FjmxNw76SJAPE")

        :param open_id:
        :return store_id, store_name:
        """

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        try:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            lng = 0
            lat = 0
            if not user:
                session.close()
                return "", "", "", "", lng, lat

            agency_uid = user.ebf_user_agency_uid
            agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
            if not agency:
                session.close()
                return "", "", "", "", lng, lat

            agency_type = agency.ebf_agency_type
            if agency_type in [AgencyType.STORE, AgencyType.SUPPLIER]:
                # 门店取自己的信息
                store = agency
                store_id = store.ebf_agency_id
            elif agency_type in [AgencyType.CLERK, AgencyType.SALES]:
                # 店员/业务员取所属门店信息
                store_id = agency.ebf_agency_parent_id
                store = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
            else:
                # 原合伙人体系取默认门店信息
                session.close()
                return "", "", "", "", lng, lat

            if not store:
                session.close()
                return "", "", "", "", lng, lat

            store_name = store.ebf_agency_name
            address = store.ebf_agency_address
            phone = store.ebf_agency_contact
            lng = store.ebf_agency_longitude if store.ebf_agency_longitude else 0
            lat = store.ebf_agency_latitude if store.ebf_agency_latitude else 0
            session.close()
            return store_id, store_name, address, phone, lng, lat

        except Exception as e:
            logger.exception(e)
            session.close()
            return "", "", "", "", lng, lat

    @staticmethod
    def get_store_info(store_agency):
        """
        获取门店信息
        高级门店用户返回门店信息，否则返回默认: '',''

        UserHelper.get_store_info("o7qyl0vKx54jB05FjmxNw76SJAPE")

        :param store_agency:
        :return store_id, store_name, address, phone, lng, lat
        """

        if store_agency:
            store_id = store_agency.ebf_agency_id
            store_name = store_agency.ebf_agency_name
            address = store_agency.ebf_agency_address
            phone = store_agency.ebf_agency_contact
            lng = store_agency.ebf_agency_longitude if store_agency.ebf_agency_longitude else 0
            lat = store_agency.ebf_agency_latitude if store_agency.ebf_agency_latitude else 0
            return store_id, store_name, address, phone, lng, lat
        return "", "", "", "", 0, 0

    @staticmethod
    def get_online_store_id(open_id):
        """
        获取用户线上门店ID
        高级门店用户返回门店信息，否则返回默认: 1

        UserHelper.get_online_store_id("o7qyl0vKx54jB05FjmxNw76SJAPE")

        :param open_id:
        :return store_id:
        """

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        try:
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            if not user:
                session.close()
                return 1

            agency_uid = user.ebf_user_agency_uid
            agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
            if not agency:
                session.close()
                return 1

            agency_id = agency.ebf_agency_id
            agency_type = agency.ebf_agency_type
            agency_sub_type = agency.ebf_agency_sub_type
            if agency_type == 3 and agency_sub_type != 0:
                store_id = agency_id
                session.close()
                return store_id
            else:
                session.close()
                return 1
        except Exception as e:
            logger.exception(e)
            session.close()
            return 1

    @staticmethod
    def get_agency_uid(open_id):
        """
        根据合伙人open_id获取uid
        :param open_id: 合伙人的open_id
        :return: agency_uid
        """
        class UserAgency(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user_agency", "model": UserAgency},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        user_agency = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if not user_agency:
            session.close()
            return None

        agency = session.query(Agency).filter_by(ebf_agency_id=user_agency.ebf_agency_id).first()
        if not agency:
            session.close()
            return None

        agency_uid = agency.ebf_agency_uid
        session.close()
        return agency_uid

    @staticmethod
    def get_agency_openid(agency_id):
        """
        查找合伙人绑定的open_id

        UserHelper.get_agency_openid(119)
        'o7qyl0i6R30kbFS7KPFVGwYb05pY'

        :param agency_id: int
        :return: agency open_id: string
        """
        class UserAgency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user_agency", "model": UserAgency},
        ])

        user_agency = session.query(UserAgency).filter_by(ebf_agency_id=agency_id).first()
        if not user_agency:
            logger.error(f"当前合伙人账户未绑定微信: agency_id={agency_id} ")
            session.close()
            return None

        agency_openid = user_agency.ebf_ua_bind_user_id
        session.close()
        return agency_openid

    @staticmethod
    def is_agency(open_id):
        """
        是否合伙人
        """
        class UserAgency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user_agency", "model": UserAgency},
        ])

        user_agency = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if not user_agency:
            logger.error(f"当前用户微信未绑定合伙人账户: {open_id=} ")
            session.close()
            return False

        session.close()
        return True

    @staticmethod
    def get_career_agency(agency_uid):
        """
        通过合伙人ID/UID获取合伙人事业部记录

        UserHelper.get_career_agency(119)

        UserHelper.get_career_agency("119")

        UserHelper.get_career_agency("f7fd0668-5a3a-11e7-9315-00a0d1ed4d50")

        """

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])

        filters = dict()
        if type(agency_uid) is int or re.match(r"^\d+$", agency_uid):
            filters["ebf_agency_id"] = agency_uid
        else:
            filters["ebf_agency_uid"] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            logger.error(f"get_career_agency: agency_uid={agency_uid} 合伙人记录不存在")
            return None

        agency_type = agency.ebf_agency_type
        agency_sub_type = agency.ebf_agency_sub_type
        # 检查当前用户自己是否为事业合伙人, 包括: 行家3.2 新事业部3.3
        if agency_type == AgencyType.CAREER or agency_type == AgencyType.STORE and agency_sub_type > 1:
            logger.info(f"get_career_agency: agency_uid={agency_uid} 该合伙人自己就是事业合伙人")
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            logger.info(f"get_career_agency: agency_uid={agency_uid} 该合伙人没有上级")
            session.close()
            return None

        # 找到级别里直属合伙人最近的事业合伙人
        career_agency = None
        agency_id = agency.ebf_agency_parent_id
        count = 0
        while agency_id and agency_id > 0:
            last_agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if last_agency:
                agency_id = last_agency.ebf_agency_parent_id
                agency_type = last_agency.ebf_agency_type
                agency_sub_type = last_agency.ebf_agency_sub_type
                count += 1
                # 检查是否为事业合伙人, 包括: 行家3.2 新事业部3.3
                if agency_type == AgencyType.CAREER or agency_type == AgencyType.STORE and agency_sub_type > 1:
                    career_agency = last_agency
                    break
                # 避免账号死循环的情况
                if count > 100:
                    logger.error(f"get_career_agency: level > 100 agency_id={agency_id}")
                    break
        logger.info(
            f"get_career_agency: agency_uid={agency_uid} career_agency_id={career_agency.ebf_agency_id if career_agency else 0}")
        session.close()
        return career_agency

    @staticmethod
    def get_super_agency(agency_uid):
        """
        通过合伙人ID/UID获取合伙人超级事业部记录

        UserHelper.get_career_agency(119)

        UserHelper.get_career_agency("119")

        UserHelper.get_career_agency("f7fd0668-5a3a-11e7-9315-00a0d1ed4d50")

        """

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])

        filters = dict()
        if type(agency_uid) is int or re.match(r"^\d+$", agency_uid):
            filters["ebf_agency_id"] = agency_uid
        else:
            filters["ebf_agency_uid"] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            logger.error(f"get_super_agency: agency_uid={agency_uid} 合伙人记录不存在")
            return None

        # 检查当前用户自己是否为超级事业合伙人：2481 雷总
        if agency_uid == "e2fcbefa-b525-11e9-a183-5254005e893b" or agency_uid == 2481:
            logger.info(f"get_super_agency: agency_uid={agency_uid} 该合伙人自己就是超级事业合伙人")
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            logger.info(f"get_super_agency: agency_uid={agency_uid} 该合伙人没有上级")
            session.close()
            return None

        # 查找最近的超级事业合伙人
        super_agency = None
        agency_id = agency.ebf_agency_parent_id
        count = 0
        while agency_id and agency_id > 0:
            last_agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if last_agency:
                # 检查是否为超级事业合伙人
                if agency_id == 2481:
                    super_agency = last_agency
                    break
                # 避免账号死循环的情况
                agency_id = last_agency.ebf_agency_parent_id
                count += 1
                if count > 100:
                    logger.error(f"get_career_agency: level > 100 agency_id={agency_id}")
                    break
        logger.info(
            f"get_super_agency: agency_uid={agency_uid} super_agency_id={super_agency.ebf_agency_id if super_agency else 0}")
        session.close()
        return super_agency

    @staticmethod
    def get_supplier_agency(agency_uid):
        """
        通过合伙人ID/UID获取合伙人所属供应商平台
        """

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])

        filters = dict()
        if isinstance(agency_uid, int) or re.match("^/d+$", agency_uid):
            filters["ebf_agency_id"] = agency_uid
        else:
            filters["ebf_agency_uid"] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            logger.error(f"get_supplier_agency: agency_uid={agency_uid} 合伙人记录不存在")
            return None

        agency_type = agency.ebf_agency_type
        # 检查当前用户自己是否为供应商账号
        if agency_type == AgencyType.SUPPLIER:
            logger.info(f"get_supplier_agency: agency_uid={agency_uid} 该账号本身就是供应商")
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            logger.info(f"get_supplier_agency: agency_uid={agency_uid} 该合伙人没有上级")
            session.close()
            return None

        # 找到级别里直属合伙人最近的供应商账号
        supplier_agency = None
        count = 0
        agency_id = agency.ebf_agency_parent_id
        while agency_id and agency_id > 0:
            last_agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if last_agency:
                agency_id = last_agency.ebf_agency_parent_id
                agency_type = last_agency.ebf_agency_type
                count += 1
                # 检查是否为供应商账号
                if agency_type == AgencyType.SUPPLIER:
                    supplier_agency = last_agency
                    break
                # 避免账号死循环的情况
                if count > 100:
                    logger.error(f"get_supplier_agency: level > 100 agency_id={agency_id}")
                    break
        logger.info(
            f"get_supplier_agency: agency_uid={agency_uid} supplier_agency_id={supplier_agency.ebf_agency_id if supplier_agency else 0}")
        session.close()
        return supplier_agency

    @staticmethod
    def get_supplier_id(agency_uid):
        """
        通过合伙人ID/UID获取合伙人所属供应商平台ID
        """
        logger.debug(f"获取合伙人供应商平台ID，agency_uid={agency_uid}")
        supplier = UserHelper.get_supplier_agency(agency_uid)
        if supplier:
            return supplier.ebf_agency_id
        else:
            return 0

    @staticmethod
    def get_user_supplier_id(open_id):
        """
        通过用户ID获取用户所属供应商平台ID
        """
        logger.debug(f"获取用户供应商平台ID，open_id={open_id}")
        user = UserHelper.get_user(open_id)
        if user:
            agency_uid = user.ebf_user_agency_uid
            supplier = UserHelper.get_supplier_agency(agency_uid)
            if supplier:
                return supplier.ebf_agency_id
        return 0

    @staticmethod
    def is_supplier_staff(agency_uid):
        """
        通过合伙人ID/UID判断是否供应商职员

        UserHelper.is_supplier_staff(119)
        False

        UserHelper.is_supplier_staff("f7fd0668-5a3a-11e7-9315-00a0d1ed4d50")
        False

        """
        agency = UserHelper.get_agency(agency_uid)
        agency_type = agency.ebf_agency_type
        supplier_id = UserHelper.get_supplier_id(agency_uid)

        if agency_type == AgencyType.SUPPLIER:
            logger.debug(f"是供应商账号: supplier_id={supplier_id}, agency_uid={agency_uid}")
            return True
        elif agency.ebf_agency_parent_id == supplier_id and agency_type == AgencyType.CLERK:
            logger.debug(f"是供应商职员账号: supplier_id={supplier_id}, agency_uid={agency_uid}")
            return True
        else:
            logger.debug(f"不是供应商职员账号: supplier_id={supplier_id}, agency_uid={agency_uid}")
            return False

    @staticmethod
    def get_agency_by_uid(agency_uid):
        """
        通过合伙人UID获取合伙人记录
        """
        logger.debug(f"获取合伙人记录，agency_uid={agency_uid}")

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])
        agency = session.query(Agency).filter_by(ebf_agency_uid=agency_uid).first()
        session.close()
        return agency

    @staticmethod
    def get_agency(agency_id):
        """
        通过合伙人ID/UID获取合伙人记录
        """
        logger.debug(f"获取合伙人记录，agency_id={agency_id}")

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])

        filters = dict()
        if isinstance(agency_id, int) or re.match("^/d+$", agency_id):
            filters["ebf_agency_id"] = agency_id
        else:
            filters["ebf_agency_uid"] = agency_id

        agency = session.query(Agency).filter_by(**filters).first()
        session.close()
        return agency

    @staticmethod
    def get_user_agency(open_id):
        """
        通过用户Open_ID获取用户所属合伙人的记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f"获取合伙人记录，open_id={open_id}")

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
        session.close()
        return agency

    @staticmethod
    def get_user_agency_uid(open_id):
        """
        通过用户Open_ID获取用户所属合伙人的UID
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f"获取合伙人记录，open_id={open_id}")

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
        session.close()
        if agency:
            return agency.ebf_agency_uid
        return config.DEFAULT_AGENCY_UID

    @staticmethod
    def get_user_agency_id(open_id):
        """
        通过用户Open_ID获取用户所属合伙人的记录
        UserHelper.get_user_agency('o7qyl0i6R30kbFS7KPFVGwYb05pY')

        :param: open_id: 用户ID
        :return: user_agency record: 用户所属合伙人记录

        """
        logger.debug(f"获取合伙人记录，open_id={open_id}")

        class User(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            session.close()
            return None

        agency = session.query(Agency).filter_by(ebf_agency_uid=user.ebf_user_agency_uid).first()
        session.close()
        return agency.ebf_agency_id

    @staticmethod
    def get_store_agency(agency_uid):
        """
        通过合伙人ID/UID获取门店合伙人对象

        :param: agency_uid: string or agency_id: int
        :return: store_agency: object

        """
        logger.debug(f"获取所属门店，agency_uid={agency_uid}")

        class GoodsOrder(object):
            pass

        class User(object):
            pass

        class Pay(object):
            pass

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_order", "model": GoodsOrder},
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_pay", "model": Pay},
            {"db_table": "ebt_agency", "model": Agency},
        ])

        filters = dict()
        if isinstance(agency_uid, int) or re.match("^/d+$", agency_uid):
            filters["ebf_agency_id"] = agency_uid
        else:
            filters["ebf_agency_uid"] = agency_uid

        agency = session.query(Agency).filter_by(**filters).first()
        if not agency:
            session.close()
            return None
        # 检查当前用户自己是否为门店
        if agency.ebf_agency_type == AgencyType.STORE:
            logger.info("该合伙人自己就是门店")
            session.close()
            return agency

        if agency.ebf_agency_parent_id == 0:
            session.close()
            return None

        # 找到级别里直属合伙人最近的门店
        store_agency = None
        agency_id = agency.ebf_agency_parent_id
        while agency_id and agency_id > 0:
            last_agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if last_agency:
                agency_id = last_agency.ebf_agency_parent_id
                if last_agency.ebf_agency_type == AgencyType.STORE:
                    store_agency = last_agency
                    break
        session.close()
        return store_agency

    @staticmethod
    def get_pickup_store_agency(open_id):
        """
        获取用户店内自提门店
        """
        user = UserHelper.get_user(open_id)
        if UserHelper.is_agency(open_id):
            # 店主及店员及门店下的合伙人获取自己所属的门店
            uid = UserHelper.get_user_agency_uid(open_id)
            store = UserHelper.get_store_agency(uid)
            if store:
                return store
        # 普通用户/非门店名下合伙人获取推荐人所属的门店
        recommender = user.ebf_user_recommend_user
        uid = UserHelper.get_agency_uid(recommender)
        if uid:
            store = UserHelper.get_store_agency(uid)
            return store
        return None

    @staticmethod
    def get_store_leader(store_id):
        """
        获取门店店长

        UserHelper.get_store_leader(296)

        :param store_id: 门店编号
        :return: store_leader 门店店长记录
        """

        class Agency:
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency},
        ])

        clerks = session.query(Agency).filter_by(
            ebf_agency_parent_id=store_id,
            ebf_agency_type=AgencyType.CLERK,
        ).order_by(Agency.ebf_agency_id.asc()).all()

        if len(clerks) > 0:
            # 绑定了多个店员，找出店长
            leaders = [w for w in clerks if w.ebf_agency_sub_type == 1]
            n = len(leaders)
            if n == 1:
                # 店长绑定唯一账号
                leader = leaders[0]
                logger.info(f"门店 {store_id} 店长是 {leader.ebf_agency_id}")
            elif n > 1:
                leader = leaders[n - 1]
                logger.error(f"门店 {store_id} 绑定了多个店长！默认最后一个: {leader.ebf_agency_id}")
            else:
                logger.info(f"门店没有绑定店长：store_id={store_id}")
                session.close()
                return None
                # 取消默认第一个店员为店长
                # leader = clerks[0]
                # logger.info(f"门店 {store_id} 店长没有绑定，默认为第一个店员: {leader.ebf_agency_id}")
            session.close()
            return leader
        else:
            # len(clerks) = 0:
            logger.error(f"门店 {store_id} 没有绑定店员账号，没有店长")
            session.close()
            return None

    @staticmethod
    def get_posts_agency(posts_id):
        """
        由点评文章ID获取作者合伙人记录

        :param recommend_id: 点评文章ID
        :return agency: 合伙人记录
        """
        db = mongodb_util.db
        posts = db.sdec_posts.find_one({"_id": posts_id})
        if not posts:
            logger.error(f"帖子不存在: {posts_id}")
            return None
        agency_id = posts.get("agency_id")
        if not agency_id:
            logger.error(f"帖子没有合伙人ID: {posts_id}")
            return None

        class Agency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_agency", "model": Agency}
        ])

        agency = None
        try:
            agency = session.query(Agency).filter_by(ebf_agency_id=agency_id).first()
            if not agency:
                logger.error(f"帖子合伙人记录不存在: agency_id={agency_id}")
        except Exception as e:
            logger.exception(e)
        finally:
            session.close()
            return agency

    @staticmethod
    def is_have_pingui_power(open_id):
        """检查用户是否具有拼柜权限"""

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
            {"db_table": "ebt_agency", "model": Agency},
            {"db_table": "ebt_user_agency", "model": UserAgency},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id, ebf_user_factory_id=config.FACTORY_ID).first()
        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()
        if ua:
            session.close()
            return True

        number = user.ebf_user_recommend_number
        if number and number >= 3:
            session.close()
            return True

        session.close()
        return False

    @staticmethod
    def is_eligible_for_trial(open_id, goods_id):
        """
        判断用户是否可以申请样品: 商品可试饮而且以前没买过

        UserHelper.is_eligible_for_trial("o7qyl0i6R30kbFS7KPFVGwYb05pY", "599103763461525")

        :param open_id:
        :param goods_id:
        :return: bool
        """
        class Goods(object):
            pass

        class Order(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_goods", "model": Goods},
            {"db_table": "sdet_order", "model": Order},
        ])

        goods = session.query(Goods).filter_by(sdef_goods_id=goods_id, sdef_goods_factory_uid=config.FACTORY_UID).first()
        if not goods.sdef_goods_is_trial:
            return False

        orders = session.query(Order).filter_by(
            sdef_order_device_id=open_id,
            sdef_order_pay_status=PayStatus.SUCCESS,
            sdef_order_factory_uid=config.FACTORY_UID,
        ).all()

        if orders:
            for o in orders:
                _goods = o.sdef_order_goods
                if _goods and goods_id in _goods:
                    return False
        return True

    @staticmethod
    def is_gift(goods_id):
        """
        判断用户是否可以申请样品: 商品可试饮而且以前没买过

        UserHelper.is_gift("599103763461525")

        :param goods_id:
        :return: bool
        """
        class Goods(object):
            pass

        session = get_db_session([
            {"db_table": "sdet_goods", "model": Goods},
        ])

        goods = session.query(Goods).filter_by(sdef_goods_id=goods_id, sdef_goods_factory_uid=config.FACTORY_UID).first()
        if not goods.sdef_goods_is_trial:
            return False

        return True

    @staticmethod
    def update_user_level(open_id, level=10):
        class User(object):
            pass

        session = get_db_session([
            {"db_table": "ebt_user", "model": User},
        ])

        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        pre_level = user.ebf_user_level
        if level > pre_level:
            user.ebf_user_level = level
            logger.info(f"update_user_level: open_id={open_id} from {pre_level} to {level}")
            session.commit()
            session.close()
            return True
        else:
            session.close()
            return False

class AddressHelper(object):
    @staticmethod
    def add(open_id, name, phone, province, city, county, detail_address, address_id, is_default=True):
        db = mongodb_util.db
        data = dict(
            user_id=open_id,
            name=name,
            phone=phone,
            province=province,
            city=city,
            county=county,
            detail_address=detail_address,
            address_id=int(address_id),
            is_default=is_default,
            is_delete=False,
            create_time=datetime.datetime.now(),
            update_time=datetime.datetime.now(),
        )
        db.sdec_address.insert(data)
        return data

    @staticmethod
    def set_default(user_id, address_id, is_default, is_use=None):
        logger.debug("set_default is_default=%s" % is_default)
        db = mongodb_util.db
        address = db.sdec_address.find_one({"user_id": user_id, "address_id": int(address_id), "is_delete": False})
        if not address:
            return None

        ret = AddressHelper.update(address["user_id"], address["name"], address["phone"],
                                   address["province"],
                                   address["city"], address["county"],
                                   address["detail_address"], address["address_id"],
                                   is_default=is_default, is_use=is_use)
        return ret

    @staticmethod
    def get_default(user_id):
        db = mongodb_util.db
        address = db.sdec_address.find_one({"user_id": user_id, "is_delete": False, "is_default": True})
        return address

    @staticmethod
    def update(open_id, name, phone, province, city, county, detail_address, address_id, is_default=None,
               new_address_id=None, is_use=None):
        db = mongodb_util.db
        logger.debug("new address_id=%s" % address_id)
        data = dict(
            user_id=open_id,
            name=name,
            phone=phone,
            province=province,
            city=city,
            county=county,
            detail_address=detail_address,
            address_id=int(address_id),
            is_delete=False,
            create_time=datetime.datetime.now(),
            update_time=datetime.datetime.now(),
        )
        if new_address_id:
            data["address_id"] = int(new_address_id)

        if is_default is not None:
            data["is_default"] = is_default
            if is_default:
                # 将其它地址更新为非默认
                logger.debug("将其它地址更新为非默认")
                db.sdec_address.update({"user_id": open_id, "is_delete": False},
                                       {"$set": {"is_default": False}}, multi=True)

        if is_use is not None:
            data["is_use"] = is_use
            if is_use:
                # 将其它地址更新为非使用
                logger.debug("将其它地址更新为非使用")
                _filter = {"user_id": open_id, "is_delete": False}
                db.sdec_address.update(_filter, {"$set": {"is_use": False}}, multi=True)

        db.sdec_address.update({"user_id": open_id, "address_id": int(address_id), "is_delete": False}, {"$set": data})
        return data

    @staticmethod
    def delete(user_id, address_id):
        db = mongodb_util.db
        db.sdec_address.update({"user_id": user_id, "address_id": int(address_id)}, {"$set": dict(
            is_delete=True,
            update_time=datetime.datetime.now(),
        )})
        return True

    @staticmethod
    def delete_address(user_id, address_id):
        db = mongodb_util.db
        db.sdec_address.remove({"user_id": user_id, "address_id": int(address_id)})
        return True

    @staticmethod
    def get_use(user_id):
        db = mongodb_util.db
        address = db.sdec_address.find_one({"user_id": user_id, "is_delete": False, "is_use": True})
        return address
